package com.andova.file

import android.os.SystemClock
import com.andova.ext.ad
import com.andova.ext.ae
import com.andova.ext.ai
import com.andova.ext.aw
import kotlinx.coroutines.delay
import java.io.File
import java.text.DateFormat
import java.text.ParseException

class FileRecovery {
    private var lock = false
    private var ignore = 0
    private var cancel = false
    private suspend fun verifyAim(file: File, aim: suspend (file: File) -> Boolean): Boolean {
        val ret = aim(file)
        delay(5L)
        if (ret) return true
        ++ignore
        if (file.isDirectory) {
            ad("aim dir $file false, ignore it")
        } else ad("aim file $file false, ignore it")
        return false
    }

    /**
     * todo [delay]放在这里面就可能很消耗cpu 而放在[verifyAim]里面就能很好的解决 这是为什么？
     */
    suspend fun recover(dir: File?, sdf: DateFormat, aim: suspend (file: File) -> Boolean) {
        cancel = false
        dir ?: return ae("$dir should not null")
        if (dir.isFile) return ae("$dir is not directory")
        if (lock) return aw("recover is busying ${Thread.currentThread()}")
        lock = true
        ignore = 0
        var suc = 0
        var fil = 0
        val start = SystemClock.currentThreadTimeMillis()
        ai("ready recover files under $dir...")
        val subdirs = mutableListOf<File>()
        for (f in dir.listFiles()) {
            if (cancel) return aw("recover canceled")
            if (f.isDirectory) {
                ai("find a sub directory $f")
                subdirs.add(f)
                continue
            }
            if (!verifyAim(f, aim)) continue
            val ret = f.delete()
            ad("find a sub file under $dir, delete it ${if (ret) "success" else "failure"}")
            if (ret) ++suc else ++fil
        }
        ai("recover files completion under $dir, success $suc, failure $fil")
        ai("ready recover ${subdirs.size} sub directory...")
        for (subdir in subdirs) {
            if (cancel) return aw("recover canceled")
            suc = 0
            fil = 0
            ad("ready recover sub dir $subdir")
            try {
                sdf.parse(subdir.name)
            } catch (e: ParseException) {
                if (!verifyAim(subdir, aim)) continue
                val ret = subdir.delete()
                aw("find an unexpected sub dir $subdir, delete it ${if (ret) "success" else "failure"}")
                continue
            }
            val filelist = subdir.listFiles()
            if (filelist.isNullOrEmpty()) {
                val ret = subdir.delete()
                aw("$subdir is empty directory, delete it ${if (ret) "success" else "failure"}")
                continue
            }
            for (f in filelist) {
                if (cancel) return aw("recover canceled")
                if (f.isDirectory) {
                    if (!verifyAim(f, aim)) continue
                    val ret = f.delete()
                    aw("find an unexpected sub dir $f under $subdir, delete it ${if (ret) "success" else "failure"}")
                    continue
                }
                if (!verifyAim(f, aim)) continue
                val ret = f.delete()
                ad("find a sub file $f under $subdir, delete it ${if (ret) "success" else "failure"}")
                if (ret) ++suc else ++fil
            }
            ai("recover files completion under $subdir, success $suc, failure $fil")
        }
        ai("recovery ${SystemClock.currentThreadTimeMillis() - start} millisecond, ignore count $ignore")
        lock = false
    }

    fun discontinue() {
        cancel = true
    }
}